﻿using System.Collections.Generic;
using System.Text;
using UnityEngine;
using XLua;

namespace Al_FrameWork
{
    [Hotfix]
    [LuaCallCSharp]
    public class XLuaManager : MonoBehaviour
    {
        private const string hotfixMainScriptName = "XLua.HotfixMain";
        private AssetBundle luaAssetBundle;

        private static XLuaManager _instance;

        public static XLuaManager Instance
        {
            get { return GlobalFunctions.GetInstance(ref _instance, "_XLuaManager", true); }
        }

        private LuaEnv _luaEnv = null;

        //加载的lua
        private Dictionary<string, TextAsset> luaScripts = new Dictionary<string, TextAsset>();

        /// <summary>
        /// LuaAssetBundle
        /// </summary>
        private AssetBundle LuaAssetBundle
        {
            get
            {
                if (luaAssetBundle == null)
                {
                    string name = GlobalFunctions.PackagePathToAssetsPath(GameConfig.LuaScriptsFolder);
                    name = GlobalFunctions.AssetBundlePathToAssetBundleName(name);
                    luaAssetBundle = ResourceManager.Instance.GetAssetBundle(name);
                    if (luaAssetBundle == null) GlobalFunctions.Err("not Found lua assetbundle=>{0}", name);
                }

                return luaAssetBundle;
            }
            set => luaAssetBundle = value;
        }

        /// <summary>
        /// Init
        /// </summary>
        public void Init()
        {
            ClearLuaAssetBundle();
            InitLuaEnv();
            InitGameConfig();
        }

        /// <summary>
        /// ClearLuaAssetBundle
        /// </summary>
        public void ClearLuaAssetBundle()
        {
            luaAssetBundle = null;
            luaScripts.Clear();
        }

        /// <summary>
        /// StartHotfix
        /// </summary>
        /// <param name="restart"></param>
        public void StartHotfix(bool restart = false)
        {
            if (_luaEnv == null) return;

            if (restart)
            {
                StopHotfix();
                ReloadScript(hotfixMainScriptName);
            }
            else
            {
                LoadScript(hotfixMainScriptName);
            }

            SafeDoString("HotfixMain.Start()");
        }

        /// <summary>
        /// InitLuaEnv
        /// </summary>
        public void InitLuaEnv()
        {
            _luaEnv = new LuaEnv();
            if (_luaEnv != null)
            {
                _luaEnv.AddLoader(CustomLoader);
            }
            else
            {
                GlobalFunctions.Err("InitLuaEnv null");
            }
        }

        /// <summary>
        /// CustomLoader
        /// </summary>
        /// <param name="scriptName"></param>
        /// <returns></returns>
        public byte[] CustomLoader(ref string scriptName)
        {
            string scriptPath = string.Empty;
            scriptName = scriptName.Replace(".", "/") + ".lua.txt";
            // GlobalFunctions.LOG("scriptName=====>{0}", scriptName);
            if (luaScripts.ContainsKey(scriptName)) return luaScripts[scriptName].bytes;
            byte[] content = null;
            TextAsset luaText = GetLuaScriptTextAsset(ref scriptName);
            if (luaText != null)
            {
                content = luaText.bytes;
            }

            if (content == null)
            {
                return null;
            }

            return content;
        }

        /// <summary>
        /// GetLuaScriptContent
        /// </summary>
        /// <param name="scriptName"></param>
        /// <returns></returns>
        public string GetLuaScriptContent(string scriptName)
        {
            if (string.IsNullOrEmpty(scriptName)) return null;
            scriptName = scriptName.Replace(".", "/") + ".lua.txt";
            if (luaScripts.ContainsKey(scriptName)) return luaScripts[scriptName].text;
            TextAsset luaText = GetLuaScriptTextAsset(ref scriptName);
            if (luaText != null) return luaText.text;
            return null;
        }

        /// <summary>
        /// ReadLuaFileContent
        /// </summary>
        /// <param name="scriptName"></param>
        /// <returns></returns>
        private byte[] ReadLuaFileContent(string scriptName)
        {
            //#if UNITY_EDITOR
            //// 这样写的原因，lua文件可能没有放在 Resources 目录下
            //            string scriptPath = string.Format("{0}/{1}/{2}/{3}", Application.dataPath, GameConfig.AssetsFolderName, GameConfig.LuaScriptsFolder, scriptName);
            //            byte [] content = UTF8Encoding.UTF8.GetBytes(GameUtility.SafeReadAllText(scriptPath));
            //            return content;
            //#else
            // print("scriptName-------------"+scriptName);
            var scriptResPath = string.Format("{0}/{1}", GameConfig.LuaScriptsFolder, scriptName);

            scriptResPath = scriptResPath.Replace(".txt", "");

            return Resources.Load<TextAsset>(scriptResPath).bytes;

//#endif       
        }

        /// <summary>
        /// GetLuaScriptTextAsset
        /// </summary>
        /// <param name="scriptName"></param>
        /// <returns></returns>
        public TextAsset GetLuaScriptTextAsset(ref string scriptName)
        {
            if (LuaAssetBundle == null) return null;
            //scriptName = scriptName.Replace(".", "/") + ".lua.txt";
            var scriptPath = string.Format("Assets/{0}/{1}/{2}", GameConfig.AssetsFolderName,
                GameConfig.LuaScriptsFolder, scriptName);
            var luaText = LuaAssetBundle.LoadAsset<TextAsset>(scriptPath);
            if (luaText == null) return null;
            luaScripts[scriptName] = luaText;
            return luaText;
        }


        /// <summary>
        /// GetLuaEnv
        /// </summary>
        /// <returns></returns>
        public LuaEnv GetLuaEnv()
        {
            return _luaEnv;
        }

        /// <summary>
        /// StopHotfix
        /// </summary>
        public void StopHotfix()
        {
            SafeDoString("HotfixMain.Stop()");
        }

        /// <summary>
        /// 安全执行
        /// </summary>
        /// <param name="scriptContent"></param>
        public void SafeDoString(string scriptContent)
        {
            if (_luaEnv != null)
            {
                try
                {
                    _luaEnv.DoString(scriptContent);
                }
                catch (System.Exception e)
                {
                    string msg = string.Format("xLua exception:{0}\n{1}", e.Message, e.StackTrace);
                    Debug.LogError(msg);
                }
            }
        }


        /// <summary>
        /// Dispose
        /// </summary>
        private void Dispose()
        {
            if (_luaEnv != null)
            {
                try
                {
                    _luaEnv.Dispose();
                    _luaEnv = null;
                }
                catch (System.Exception ex)
                {
                    Debug.LogError(ex.Message);
                }
            }
        }

        /// <summary>
        /// 重启lua虚拟机，热更资源以后被加载的lua脚本可能已经过时，需要重新加载
        /// </summary>
        public void Restart()
        {
            StopHotfix();
            ClearLuaAssetBundle();
            Dispose();
            InitLuaEnv();
            InitGameConfig();
        }

        /// <summary>
        /// ReloadScript
        /// </summary>
        /// <param name="scriptName"></param>
        public void ReloadScript(string scriptName)
        {
            SafeDoString(string.Format("package.loaded['{0}'] = nil", scriptName));
            LoadScript(scriptName);
        }


        /// <summary>
        /// LoadScript
        /// </summary>
        /// <param name="scriptName"></param>
        void LoadScript(string scriptName)
        {
            SafeDoString(string.Format("require('{0}')", scriptName));
        }

        /// <summary>
        /// InitGameConfig
        /// </summary>
        private void InitGameConfig()
        {
            // _luaEnv.DoString("_G.GAME_SERVER_URI = \"" + GameConfig.Uri + "\"");
            // _luaEnv.DoString("_G.GAME_ENABLE_UI_LAYER_MANAGER = true");
            // if (GameConfig.IsNeiwang)
            // {
            //     _luaEnv.DoString("_G.USE_SERVER = \"neiwang\"");
            // }
            // else
            // {
            //     _luaEnv.DoString("_G.USE_SERVER = \"waiwang\"");
            // }
            //
            // if (GameConfig.EnablePatch)
            // {
            //     _luaEnv.DoString("_G.ENABLE_PATH = true");
            //     //标记游戏由patch 场景进入
            //     _luaEnv.DoString("_G.BY_PATCH_ENTER = true");
            // }
            // else
            // {
            //     _luaEnv.DoString("_G.ENABLE_PATH = false");
            // }
        }
    }
}